package com.zhuxulin.midi.util;

import com.zhuxulin.midi.event.MidiEvent;
import com.zhuxulin.midi.event.meta.TimeSignature;

/**
 * An event specifically for MidiProcessor to broadcast metronome ticks
 * so that observers need not rely on time conversions or measure tracking
 */
public class MetronomeTick extends MidiEvent {
	
	private int mResolution;
	private TimeSignature mSignature;
	
	private int mCurrentMeasure;
	private int mCurrentBeat;
	
	private double mMetronomeProgress;
	private int mMetronomeFrequency;
	
	public MetronomeTick(TimeSignature sig, int resolution) {
		super(0, 0);
		
		mResolution = resolution;
		
		setTimeSignature(sig);
		mCurrentMeasure = 1;
	}
	
	public void setTimeSignature(TimeSignature sig) {
		
		mSignature = sig;
		mCurrentBeat = 0;
		
		setMetronomeFrequency(sig.getMeter());
	}
	
	public boolean update(double ticksElapsed) {
		
		mMetronomeProgress += ticksElapsed;
		
		if(mMetronomeProgress >= mMetronomeFrequency) {
			
			mMetronomeProgress %= mMetronomeFrequency;
			
			mCurrentBeat = (mCurrentBeat + 1) % mSignature.getNumerator();
			if(mCurrentBeat == 0) {
				mCurrentMeasure++;
			}
			
			return true;
		}
		return false;
	}
	
	public void setMetronomeFrequency(int meter) {
		
		switch(meter) {
		case TimeSignature.METER_EIGHTH:
			mMetronomeFrequency = mResolution / 2;
			break;
		case TimeSignature.METER_QUARTER:
			mMetronomeFrequency = mResolution;
			break;
		case TimeSignature.METER_HALF:
			mMetronomeFrequency = mResolution * 2;
			break;
		case TimeSignature.METER_WHOLE:
			mMetronomeFrequency = mResolution * 4;
			break;
		}
	}
	
	public int getBeatNumber() {
		return mCurrentBeat + 1;
	}
	public int getMeasure() {
		return mCurrentMeasure;
	}
	
	@Override
	public String toString() {
		return "Metronome: " + mCurrentMeasure + "\t" + getBeatNumber();
	}

	@Override
	public int compareTo(MidiEvent o) {
		return 0;
	}

	@Override
	protected int getEventSize() {
		return 0;
	}
	
	@Override
	public int getSize() {
		return 0;
	}
	/**
	 * Not use
	 */
	@Override
	public byte[] getCmd() {
		// TODO Auto-generated method stub
		return null;
	}
}
